#ifndef _COOLANGAGE_INSTRUCTION_H_
#define _COOLANGAGE_INSTRUCTION_H_

#include "Type.h"
#include "Expression.h"
#include <vector>
namespace COOLangage {
  class Instruction;
  class Bloc;
  class Sequence;
  class Conditionnelle;
  class ExprInstruction;
  class InstructionReturn;
  class Boucle;
  class Affectation;
  class DeclarationVariable;
}

#include "VisitorInstruction.h"


namespace COOLangage {
  // --------------------------------------------------------------------------------
  class Instruction{
  public:
    Instruction();
    virtual ~Instruction() throw();

    VisitorResult visit(VisitorInstruction *visitor);
  };

  // --------------------------------------------------------------------------------
  class Bloc : public Instruction {
    Instruction* corps;
  public:
    Bloc(Instruction *corps);
    virtual ~Bloc() throw();
  
    Instruction* getCorps() const ;
    VisitorResult visit(VisitorInstruction *visitor);
  };
  // --------------------------------------------------------------------------------
  class Sequence : public Instruction {
    std::vector<Instruction*> seq;
  public:
    Sequence();
    virtual ~Sequence() throw() ;

    int size() const;
    std::vector<Instruction*> getSequence() const;
    VisitorResult visit(VisitorInstruction *visitor);
  };

  // --------------------------------------------------------------------------------
  class Conditionnelle : public Instruction {
    Expression* condition;
    Instruction* consequence;
    Instruction* alternant;
  public:
    Conditionnelle(Expression *cond, Instruction* cons, Instruction* alt);
    virtual ~Conditionnelle() throw();

    Expression* getCondition() const;
    Instruction* getConsequence() const;
    Instruction* getAlternant() const;
    VisitorResult visit(VisitorInstruction *visitor);
  };

  // --------------------------------------------------------------------------------
  class ExprInstruction : public Instruction {
    Expression* expr;
  public:
    ExprInstruction(Expression *expr);
    virtual ~ExprInstruction() throw();

    Expression* getExpression() const;
    VisitorResult visit(VisitorInstruction *visitor);
  
  };
  // --------------------------------------------------------------------------------
  class InstructionReturn : public Instruction {
    Expression* expr;
  public:
    InstructionReturn(Expression *expr);
    virtual ~InstructionReturn() throw();

    Expression* getExpression() const;
    VisitorResult visit(VisitorInstruction *visitor);
  
  };

  // --------------------------------------------------------------------------------
  class Boucle : public Instruction {
    Expression* condition;
    Instruction* corps;
  public:
    Boucle(Expression* cond, Instruction* corps);
    virtual ~Boucle() throw();
  
    Expression* getCondition() const;
    Instruction* getCorps() const;
    VisitorResult visit(VisitorInstruction *visitor);
  };

  // --------------------------------------------------------------------------------
  class Affectation : public Instruction {
    Variable* variable;
    Expression* valeur;
  public:
    Affectation(Variable *v, Expression *e);
    virtual ~Affectation() throw();

    Variable* getVariable() const;
    Expression* getValeur() const;
    VisitorResult visit(VisitorInstruction *visitor);
  };

  // --------------------------------------------------------------------------------
  class DeclarationVariable : public Instruction {
    Type* type;
    Variable *variable;
  public:
    DeclarationVariable(Type *type, Variable* variable);
    virtual ~DeclarationVariable() throw();

    Type* getType() const;
    Variable* getVariable() const;
    VisitorResult visit(VisitorInstruction *visitor);
  };

}
#endif 
